﻿using System;
using System.IO;
using System.IO.IsolatedStorage;
using System.Text.RegularExpressions;
using System.Threading;
using System.Windows;
using System.Windows.Media.Imaging;
using GBAExtentionLib;
using GarboDev;
using CJToolkit.Util;

namespace GBAEmulator
{
    public partial class GBAEmulatorPage
    {
        private GbaManager _gbaManager;

        public GBAEmulatorPage()
        {
            InitializeComponent();
            Loaded += (sender, e) =>
                {
                    InitialGBAManager();
                    LoadBios();
                };
        }

        void InitialGBAManager()
        {
            _gbaManager=new GbaManager();
            SetRender();

            new Thread(()=>
            {
                while (true)
                {
                    try
                    {
                        CheckKeyHit();
                        Thread.Sleep(20);
                    }
                    catch (Exception)
                    {
                        throw;
                    }
                }
            }).Start();

            //new Thread(() =>
            //{
            //    while (true)
            //    {
            //        CheckFrame();
            //        Thread.Sleep(1);
            //    }
            //}).Start();
        }

        private void SetRender()
        {
            bool wasHalted = _gbaManager.Halted;
            _gbaManager.Halt();
            _gbaManager.VideoManager.Presenter = Render2D;

            var renderer = new Renderer();
            renderer.Initialize(null);

            _gbaManager.VideoManager.Renderer = renderer;
            
            if (!wasHalted)
            {
                _gbaManager.Resume();
            }
        }

        void LoadBios()
        {
            try
            {
                using (var stream =Application.GetResourceStream(new Uri("/GBAEmulator;component/bios.bin",UriKind.Relative)).Stream)//FileStream(this.biosFilename, FileMode.Open))
                {
                    var rom = new byte[(int)stream.Length];
                    stream.Read(rom, 0, (int)stream.Length);

                    _gbaManager.LoadBios(rom);
                }
                _gbaManager.Resume();
            }
            catch (Exception exception)
            {
                MessageBox.Show("Unable to load bios file, disabling bios (irq's will not work)\n" + exception.Message);
            }
        }

        [Obsolete("测试使用",true)]
        void LoadRom()
        {
            using (var stream = Application.GetResourceStream(new Uri("/GBAEmulator;component/Game.gba",UriKind.Relative)).Stream)
            {
                int romSize = 1;
                while (romSize < stream.Length)
                {
                    romSize <<= 1;
                }

                var rom = new byte[romSize];
                stream.Read(rom, 0, (int)stream.Length);

                _gbaManager.LoadRom(rom);
            }
            _gbaManager.Resume();
        }

        void LoadRom(Stream stream)
        {
            int romSize = 1;
            while (romSize < stream.Length)
            {
                romSize <<= 1;
            }

            var rom = new byte[romSize];
            stream.Read(rom, 0, (int) stream.Length);

            _gbaManager.LoadRom(rom);

            _gbaManager.Resume();
        }

        private const string SavePath = "GameSave";
        private string _gameName = string.Empty;

        private void LoadGameClick(object sender, RoutedEventArgs e)
        {
            _gbaManager.Halt();
            GBAWatcherService.Start(GBAFileChooser, fileSelectorEvent =>
                {
                    if(fileSelectorEvent==null)
                    {
                        _gbaManager.Resume();
                        return;
                    }
                    var stream =
                        new IsolatedStorageFileStream(
                            fileSelectorEvent.SelectedFile.FullName, FileMode.Open,
                            IsolatedStorageFile.GetUserStoreForApplication());
                    LoadRom(stream);
                    _gameName = Regex.Replace(fileSelectorEvent.SelectedFile.Name, ".gba$", "");
                });
        }

        //private MemorySave _save;

        private void SaveClick(object sender, RoutedEventArgs e)
        {
            //_save = gbaManager.Save();
            if (string.IsNullOrEmpty(_gameName)) return;
            _gbaManager.Halt();
            using (var storage = IsolatedStorageFile.GetUserStoreForApplication())
            {
                if (!storage.DirectoryExists(SavePath))
                    storage.CreateDirectory(SavePath);
                if (!storage.DirectoryExists(string.Format("{0}\\{1}", SavePath, _gameName)))
                    storage.CreateDirectory(string.Format("{0}\\{1}", SavePath, _gameName));
                if (storage.FileExists(string.Format("{0}\\{1}\\{2}", SavePath, _gameName, "game.sav")))
                    storage.DeleteFile(string.Format("{0}\\{1}\\{2}", SavePath, _gameName, "game.sav"));
                using (var stream = storage.OpenFile(string.Format("{0}\\{1}\\{2}",SavePath,_gameName,"game.sav"), FileMode.OpenOrCreate))
                {
                    var save = _gbaManager.Save();
                    GameSaveHandler.Save(stream, save);
                    stream.Flush();
                    stream.Close();
                    stream.Dispose();
                }
            }

            _gbaManager.Resume();
        }

        private void LoadClick(object sender, RoutedEventArgs e)
        {
            if (string.IsNullOrEmpty(_gameName)) return;
            using (var storage = IsolatedStorageFile.GetUserStoreForApplication())
            {
                if (!storage.FileExists(string.Format("{0}\\{1}\\{2}", SavePath, _gameName, "game.sav"))) return;
                _gbaManager.Halt();
                using (
                    var stream =
                        IsolatedStorageFile.GetUserStoreForApplication().OpenFile(
                            string.Format("{0}\\{1}\\{2}", SavePath, _gameName, "game.sav"), FileMode.Open)
                    )
                {
                    var save = GameSaveHandler.Load(stream);
                    stream.Flush();
                    stream.Close();
                    _gbaManager.LoadSave(save);
                    stream.Dispose();
                }
            }
            //gbaManager.LoadSave(_save);
            _gbaManager.Resume();
        }

        private void Render2D(object data)
        {
            if (data == null) return;
            var realData = (uint[]) data;
            new Thread(() =>
                {
                    var dt=new int[realData.Length];
                    for (int i = 0; i < realData.Length; i++)
                    {
                        dt[i] = realData[i].GetColorInteger();
                    }
                    Dispatcher.BeginInvoke(() =>
                    {
                        var bitmap = new WriteableBitmap(240, 160);
                        Array.Copy(dt, bitmap.Pixels, bitmap.Pixels.Length);
                        //dt.CopyTo(bitmap.Pixels, 240 * 160);
                        //for (int i = 0; i < realData.Length; i++)
                        //{
                        //    bitmap.Pixels[i] = realData[i].GetColorInteger();
                        //}
                        Monitor.Source = bitmap;
                    });
                }).Start();
            
        }
        
        private void CheckKeyHit()
        {
            _gbaManager.KeyState = GameButtonKeyService.GetInstance().GetKeyStates();
        }

    }
}